// src/api/directus.ts
import axios, { AxiosError } from "axios";

/** 计算 baseURL：支持开发代理、生产混合协议降级为代理等 */
function computeBaseURL() {
  const envUrl = (import.meta.env.VITE_DIRECTUS_URL as string | undefined)?.trim();
  const cleaned = (envUrl || "/directus").replace(/\/+$/, "");

  // 开发环境或强制代理：走 /directus 代理（避免跨域/证书问题）
  if (import.meta.env.DEV || String(import.meta.env.VITE_FORCE_PROXY || "") === "1") {
    return "/directus";
  }

  // 生产环境：如果页面是 https 而你配置了 http 直连，自动切换到代理，避免混合内容
  if (typeof window !== "undefined") {
    const isHttpsApp = window.location.protocol === "https:";
    const isHttpAbs = /^http:\/\//i.test(cleaned);
    if (isHttpsApp && isHttpAbs) return "/directus";
  }

  return cleaned || "/directus";
}

export const DIRECTUS_URL = computeBaseURL();

/** -------------------- Token 管理 -------------------- */
/** 优先级：env -> runtime 内存 -> localStorage -> sessionStorage -> window.__DIRECTUS_TOKEN__ */
let RUNTIME_TOKEN =
  (import.meta.env.VITE_DIRECTUS_STATIC_TOKEN as string | undefined)?.trim() || "";

function readTokenFromStorage(): string {
  try {
    const ls = localStorage.getItem("DIRECTUS_TOKEN")?.trim();
    if (ls) return ls;
  } catch {}
  try {
    const ss = sessionStorage.getItem("DIRECTUS_TOKEN")?.trim();
    if (ss) return ss;
  } catch {}
  try {
    // @ts-ignore
    const w = typeof window !== "undefined" ? window.__DIRECTUS_TOKEN__ : "";
    if (w && typeof w === "string") return w.trim();
  } catch {}
  return "";
}

/** 获取当前 token（环境变量/运行时/存储/全局变量 兜底） */
export function getDirectusToken(): string {
  return RUNTIME_TOKEN || readTokenFromStorage();
}

/** 运行时更新 token（例如登录/切换账号后调用），并同步到 localStorage */
export function setDirectusToken(token?: string | null, persist: boolean = true) {
  RUNTIME_TOKEN = (token || "").trim();
  if (persist) {
    try {
      if (RUNTIME_TOKEN) localStorage.setItem("DIRECTUS_TOKEN", RUNTIME_TOKEN);
      else localStorage.removeItem("DIRECTUS_TOKEN");
    } catch {}
  }
}

const DEBUG = String(import.meta.env.VITE_DEBUG_API || "") === "1";

/** -------------------- Axios 实例 -------------------- */
export const directus = axios.create({
  baseURL: DIRECTUS_URL,
  withCredentials: false,
  headers: { Accept: "application/json" },
  timeout: 20000,
});

/** 请求拦截：无论 dev 或 prod，始终带上 Authorization */
directus.interceptors.request.use((config) => {
  if (!config.headers) config.headers = {};

  const token = getDirectusToken();
  if (token) {
    // 始终附加 Authorization 头
    (config.headers as any).Authorization = `Bearer ${token}`;
  }

  if (DEBUG) {
    const base = (config.baseURL || "").replace(/\/+$/, "");
    const url = (config.url || "").replace(/^\//, "/");
    const qs = config.params ? new URLSearchParams(config.params as any).toString() : "";
    const method = (config.method || "GET").toUpperCase();
    const masked = token ? token.slice(0, 6) + "...(len:" + token.length + ")" : "none";
    console.log(
      `[directus] ${method} ${base}${url}${qs ? "?" + qs : ""} | Authorization: ${
        token ? "Bearer " + masked : "none"
      }`
    );
  }
  return config;
});

/** 统一错误对象 */
class ApiError extends Error {
  status?: number;
  code?: string | number;
  constructor(message: string, status?: number, code?: string | number) {
    super(message);
    this.status = status;
    this.code = code;
  }
}

/** 响应拦截：统一抛出 ApiError */
directus.interceptors.response.use(
  (r) => r,
  (err: AxiosError<any>) => {
    const status = err.response?.status;
    const data = err.response?.data;
    const msg = data?.errors?.[0]?.message || data?.message || err.message || "Network Error";
    const code = data?.errors?.[0]?.extensions?.code || data?.code;
    if (DEBUG) console.error("[directus:error]", status, code, msg, data);
    return Promise.reject(new ApiError(msg, status, code));
  }
);

/** sort 归一化 */
function normalizeSort(sort?: string | string[]) {
  if (!sort || (Array.isArray(sort) && !sort.length)) return undefined;
  return Array.isArray(sort) ? sort.join(",") : sort;
}

/** -------------------- 通用 CRUD -------------------- */
export async function getItems<T = any>(
  collection: string,
  params?: {
    page?: number;
    limit?: number;
    sort?: string | string[];
    fields?: string[];
    filter?: Record<string, any>;
    search?: string;
    meta?: string | string[];
    signal?: AbortSignal;
  }
): Promise<{ data: T[]; meta?: any }> {
  const res = await directus.get(`/items/${collection}`, {
    params: {
      page: params?.page,
      limit: params?.limit,
      sort: normalizeSort(params?.sort),
      fields: params?.fields,
      filter: params?.filter,
      search: params?.search,
      meta: params?.meta,
    },
    signal: params?.signal,
  });
  return { data: res.data?.data ?? [], meta: res.data?.meta };
}

export async function getItemById<T = any>(
  collection: string,
  id: string | number,
  params?: { fields?: string[]; filter?: Record<string, any>; signal?: AbortSignal }
): Promise<T> {
  const res = await directus.get(`/items/${collection}/${id}`, {
    params: { fields: params?.fields, filter: params?.filter },
    signal: params?.signal,
  });
  return res.data?.data as T;
}

export async function createItem<T = any>(collection: string, payload: Partial<T>): Promise<T> {
  const res = await directus.post(`/items/${collection}`, payload);
  return res.data?.data as T;
}

export async function updateItem<T = any>(
  collection: string,
  id: string | number,
  payload: Partial<T>
): Promise<T> {
  const res = await directus.patch(`/items/${collection}/${id}`, payload);
  return res.data?.data as T;
}

export async function updateItems<T = any>(
  collection: string,
  rows: Array<Partial<T> & { id: string | number }>
): Promise<T[]> {
  const res = await directus.patch(`/items/${collection}`, rows);
  return res.data?.data as T[];
}

export async function deleteItem(collection: string, id: string | number): Promise<void> {
  await directus.delete(`/items/${collection}/${id}`);
}

export async function deleteItems(collection: string, ids: Array<string | number>): Promise<void> {
  if (!ids.length) return;
  try {
    await directus.delete(`/items/${collection}`, { data: ids });
  } catch {
    await Promise.all(ids.map((id) => deleteItem(collection, id)));
  }
}
